// =========== the area of tick cross drawing =========== //
class cdrawArea {
  // === constructor === //
  cdrawArea(int w, int h, int x, int y) {
    this.w = w;
    this.h = h;
    this.x = x;
    this.y = y;

    scanX = new int[100];
    scanY = new int[100];

    imgSmile = loadImage("smile.png");
    imgCry = loadImage("cry.png");
    imgQuestion = loadImage("question.png");

    diff = new cdiff();

    layerDraw = createGraphics(w, h);
    layerDraw.beginDraw();
    layerDraw.fill(fg);
    layerDraw.stroke(fg);
    layerDraw.background(bg);
    layerDraw.endDraw();

    layerRslt = createGraphics(280, 280);
  }

  // === paint of main window === //
  void paint() {
    image(layerDraw, x, y);
    image(layerRslt, 460, 80);
  }

  // === if mouse moveing inside checking box === //
  boolean inArea() {
    int mx = mouseX;
    int my = mouseY;
    if (mx < x) {
      return false;
    }
    if (mx > (x + w)) {
      return false;
    }
    if (my < y) {
      return false;
    }
    if (my > (y + h)) {
      return false;
    }
    return true;
  }

  // === scan mouse moving === //
  void scan() {
    switch(sm) {
    case 0:
      {
        if (mousePressed && inArea()) {
          layerDraw.beginDraw();
          layerDraw.background(bg);
          layerDraw.endDraw();

          layerRslt.beginDraw();
          layerRslt.background(colorMainBg);
          layerRslt.endDraw();

          cnt = 0;
          sm = 1;
        }
        break;
      }
    case 1:
      {
        scanX[cnt] = mouseX;
        scanY[cnt] = mouseY;
        if (++cnt >= 100) {
          sm = 2;
        }
        break;
      }
    case 2:
      {
        int rslt = diff.calculate(scanX, tickX, "abs");
        PImage imgRslt;

        println("\n\n===== " + (++roundCnt));
        println("diff tick X = " + rslt);
        if (rslt < thresT) {
          rslt = diff.calculate(scanY, tickY, "abs");
          println("diff tick Y = " + rslt);
          if (rslt < thresT) {
            println("tick");
            imgRslt = imgSmile;
          } else {
            println("UNKNOWN 1");
            imgRslt = imgQuestion;
          }
        } else {
          rslt = diff.calculate(scanX, crossX, "abs");
          println("diff cross X = " + rslt);
          if (rslt < thresC) {
            rslt = diff.calculate(scanY, crossY, "abs");
            println("diff cross Y = " + rslt);
            if (rslt < thresC) {
              println("cross");
              imgRslt = imgCry;
            } else {
              println("UNKNOWN 2");
              imgRslt = imgQuestion;
            }
          } else {
            println("UNKNOWN 3");
            imgRslt = imgQuestion;
          }
        }

        layerRslt.beginDraw();
        layerRslt.image(imgRslt, 0, 0);
        layerRslt.endDraw();

        sm = 0;
        break;
      }
    default:
      {
        // no action, other cases is for threadShowTrace()
        break;
      }
    }
  }

  // === paint the trace when mouse moving (during scan mode) === //
  void paintTrace() {
    if (sm != 0 && sm < 100) { // 100, 101, 102 is for showPreRecTrace(), threadShowPreRecTrace()
      layerDraw.beginDraw();
      layerDraw.circle(mouseX - x, mouseY - y, 9);
      layerDraw.endDraw();
    }
  }

  // === recording mode === //
  void recStart() {
    if (sm == 0) {
      layerDraw.beginDraw();
      layerDraw.background(bg);
      layerDraw.endDraw();
      println("rec mode triggered");
      logx = createWriter("logx.log");
      logy = createWriter("logy.log");
      cnt = 0;
      sm = 1;
      nrecording = false;
      thread("threadRec");
    }
  }

  // === recording tick/corss mouseX/Y moving data === //
  void rec() { // call it in a 10ms thread (100 samples per sec)
    if (inArea()) {
      switch(sm) {
      case 0:
        {
          // standby, do nothing
          break;
        }
      case 1:
        {
          if (mousePressed) {
            println("rec starting...");
            sm = 2;
          }
          break;
        }
      case 2:
        {
          scanX[cnt] = mouseX;
          scanY[cnt] = mouseY;
          if (++cnt >= 100) {
            sm = 3;
          }
          break;
        }
      case 3:
        {
          nrecording = true;
          for (int i = 0; i < 100; i++) {
            // format fits the java array, just copy paste into code
            // final int crossX[] etc...
            logx.println(scanX[i] + ", // " + i);
            logy.println(scanY[i] + ", // " + i);
          }

          logx.flush();
          logx.close();
          logy.flush();
          logy.close();
          println("rec mode stopped\n");
          sm = 0;
          break;
        }
      }
    }
  }

  // === if recording is on going === //
  boolean isnrecording() {
    return nrecording;
  }

  // === show pre-recorded trace for reference === //
  void showPreRecTrace(int k) { // k = 't' or 'c' or 0
    if (k == (int)'t') { // 't'
      arrx = tickX;
      arry = tickY;
      sm = 100;
      showingPreRecTrace = true;
      println("\nshowing pre-recorded trace of tick ...");
      thread("threadShowPreRecTrace");
    } else if (k == (int)'c') { // 'c'
      arrx = crossX;
      arry = crossY;
      sm = 100;
      showingPreRecTrace = true;
      println("\nshowing pre-recorded trace of cross ...");
      thread("threadShowPreRecTrace");
    } else if (k == 0) { // 0
      switch(sm) {
      case 100:
        {
          layerRslt.beginDraw();
          layerRslt.background(colorMainBg);
          layerRslt.textSize(30);
          layerRslt.text("showing\npre-recorded\ntrace...", 10, 210);
          layerRslt.endDraw();

          layerDraw.beginDraw();
          layerDraw.background(bg);
          layerDraw.endDraw();

          cnt = 0;
          sm++;
          break;
        }

      case 101:
        {
          layerDraw.beginDraw();
          layerDraw.circle(arrx[cnt] - x, arry[cnt] - y, 9);
          layerDraw.endDraw();
          if (++cnt >= 100) {
            sm++;
          }
          break;
        }

      case 102:
        {
          layerRslt.beginDraw();
          layerRslt.background(colorMainBg);
          layerRslt.text("done", 10, 280);
          layerRslt.endDraw();
          showingPreRecTrace = false;
          sm = 0;
          break;
        }
      }
    }
  }

  // === if not is showing pre-recorded trace === //
  boolean isShowingPreRecTrace() {
    return showingPreRecTrace;
  };

  // === private var === //
  private int roundCnt = 0;

  private final int w, h, x, y;
  private PGraphics layerDraw;
  private final color bg = #5CC612;
  private final color fg = #D89C42;

  private int sm = 0;
  private PrintWriter logx, logy;
  private int cnt;
  private boolean nrecording = true;

  int scanX[], scanY[];

  private cdiff diff;
  private final int thresT = 4000; // threshold of tick checking
  private final int thresC = 5000; // threshold of cross checking

  private PImage imgSmile, imgCry, imgQuestion;
  private PGraphics layerRslt; // show final detect result

  private int arrx[], arry[];
  private boolean showingPreRecTrace = false;
};

// =========== object =========== //
cdrawArea drawArea;
